using System.Linq.Expressions;
using WeatherSystem.API.Specifications;
using WeatherSystem.API.Models;

namespace WeatherSystem.API.Repositories
{
    /// <summary>
    /// Read-only repository interface for query operations
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface IReadRepository<T> where T : class
    {
        Task<T?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
        Task<IEnumerable<T>> GetAllAsync(CancellationToken cancellationToken = default);
        Task<IEnumerable<T>> GetBySpecificationAsync(ISpecification<T> specification, CancellationToken cancellationToken = default);
        Task<T?> GetSingleBySpecificationAsync(ISpecification<T> specification, CancellationToken cancellationToken = default);
        Task<int> CountAsync(ISpecification<T>? specification = null, CancellationToken cancellationToken = default);
        Task<bool> AnyAsync(ISpecification<T>? specification = null, CancellationToken cancellationToken = default);
        Task<PagedResult<T>> GetPagedAsync(int page, int pageSize, ISpecification<T>? specification = null, CancellationToken cancellationToken = default);
        
        // 高性能查询方法
        Task<IEnumerable<TResult>> GetProjectedAsync<TResult>(Expression<Func<T, TResult>> projection, ISpecification<T>? specification = null, CancellationToken cancellationToken = default);
        Task<PagedResult<TResult>> GetProjectedPagedAsync<TResult>(Expression<Func<T, TResult>> projection, int page, int pageSize, ISpecification<T>? specification = null, CancellationToken cancellationToken = default);
    }

    /// <summary>
    /// Write repository interface for command operations
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface IWriteRepository<T> where T : class
    {
        Task<T> AddAsync(T entity, CancellationToken cancellationToken = default);
        Task<IEnumerable<T>> AddRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken = default);
        Task UpdateAsync(T entity, CancellationToken cancellationToken = default);
        Task UpdateRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken = default);
        Task DeleteAsync(T entity, CancellationToken cancellationToken = default);
        Task DeleteAsync(Guid id, CancellationToken cancellationToken = default);
        Task DeleteRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken = default);
        Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
    }

    /// <summary>
    /// Combined read-write repository interface (for backward compatibility)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface IRepository<T> : IReadRepository<T>, IWriteRepository<T> where T : class
    {
    }

    /// <summary>
    /// Weather data specific read repository
    /// </summary>
    public interface IWeatherDataReadRepository : IReadRepository<WeatherDataEntry>
    {
        Task<WeatherDataEntry?> GetLatestByCityAsync(Guid cityId, CancellationToken cancellationToken = default);
        Task<IEnumerable<WeatherDataEntry>> GetHistoryAsync(Guid cityId, DateTime startDate, DateTime endDate, CancellationToken cancellationToken = default);
        Task<PagedResult<Dictionary<string, object>>> GetWeatherDataPagedAsync(int page, int pageSize, Guid? cityId = null, DateTime? startDate = null, DateTime? endDate = null, string? source = null, string? sortBy = null, string? sortDirection = null, CancellationToken cancellationToken = default);
        Task<IEnumerable<Dictionary<string, object>>> GetWeatherDataAsDictionaryAsync(Expression<Func<WeatherDataEntry, bool>>? predicate = null, CancellationToken cancellationToken = default);
    }

    /// <summary>
    /// Weather data specific write repository
    /// </summary>
    public interface IWeatherDataWriteRepository : IWriteRepository<WeatherDataEntry>
    {
        Task<List<Guid>> CreateBatchAsync(List<CreateDynamicWeatherDataRequest> requests, CancellationToken cancellationToken = default);
        Task<bool> UpdateWeatherDataAsync(Guid id, UpdateDynamicWeatherDataRequest request, CancellationToken cancellationToken = default);
        Task InvalidateCacheAsync(Guid cityId, CancellationToken cancellationToken = default);
    }
}